/* ***** BEGIN LICENSE BLOCK *****
 *
 * TakeControl Firefox extension
 * Copyright (C) 2006  Dafydd Jones <takecontrol.extension@googlemail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 * Boston, MA  02110-1301, USA.
 *
 * ***** END LICENSE BLOCK ***** */

const tkctrlDEBUG = true; /* set to false to suppress debug messages */

const CC = Components.classes;
const CI = Components.interfaces;

const TKCTRL_SERVICE_CID = "@takecontrol/service;1";
const TKCTRL_OBSERVICE_CID = "@mozilla.org/observer-service;1";
const TKCTRL_TIMER_CID = "@mozilla.org/timer;1";
const TKCTRL_PREFS_CID = "@mozilla.org/preferences-service;1";

function TkctrlClient() {};
TkctrlClient.prototype = {
	toString: function() { return "tkctrl client" },
	debug: function(s) {},
	prefs: null,
	service: null,
	observer: null,
	events: ["pageshow", "pagehide", "focus", "blur", "mousedown", /*"mouseout",*/ "DOMMouseScroll", "keydown" ],
	tabbrowser: null,
	idleTimer: null,
	
	onLoad: function() {
		this.debug("load");
		this.service = CC[TKCTRL_SERVICE_CID].getService()
								.QueryInterface(CI.ITakeControlService);
		this.debug("got service?: " + this.service);

		for each (var event in this.events) { window.addEventListener(event, this, true); }

		this.observer = new Observer(this);

		var tooltip = document.getElementById("tkctrl-tooltip");
		if (tooltip) {
			this.debug("tooltip exists onload");
			tooltip.addEventListener("popupshowing", this, false);
		}
		else
			this.debug("tooltip not found");

		this.prefs = CC[TKCTRL_PREFS_CID].getService(CI.nsIPrefService);
		this.prefs = this.prefs.getBranch("extensions.takecontrol.");
		
		this.idleTimer = new IdleTimer(this.prefs, this.observer);
		this.idleTimer.start();

		// During initialisation
		this.tabbrowser = document.getElementById("content");
		
		this.tabbrowser.mPanelContainer.addEventListener("DOMNodeInserted", this, false);
		this.tabbrowser.mPanelContainer.addEventListener("select", this, false);
	},

	onUnload: function() {
		this.debug("unload");
		if (this.observer) { this.observer.unregister(); }

		for each (var event in this.events) { window.removeEventListener(event, this, true); }
	},

	displayPanel: function() {
		if (this.service) {
			var showSeconds = this.prefs.getBoolPref("showseconds");
			document.getElementById("tkctrl-label").value 
				= formatTime(this.service.siteDuration, showSeconds);
			document.getElementById("tkctrl-panel").className 
				= (this.service.paused || !this.service.active) ? 
													"inactive" : "active";

			var seconds = this.prefs.getBoolPref("showtickingclock") ? 
							this.service.siteDuration : 3;	// 3 makes the "hand" point slightly off midnight

			tkctrlDrawClock(document.getElementById("tkctrl-canvas"), seconds, 
							this.service.paused, this.service.active, false);
		}
	},

	displayTooltip: function() {
		var timeToday = document.getElementById("tkctrl-tooltip-timeToday");
		if (this.service && timeToday) 
			timeToday.value = formatTime(this.service.totalDuration, true);
	},

	openReportWindow: function() {
		this.debug("opening report window");
		var report = window.open('chrome://takecontrol/content/report.xul', 'TakeControl_report', 
									'width=500, height=230, centerscreen, chrome, resizable=yes, dependent=yes');
	},
	
	togglePaused: function(event) {		
		this.debug("togglePaused(" + event.type + ":" + event.button + ")");
		
		// a right click also triggers this event, we don't want that
		if (event.button == 2) { this.debug("cancelled"); return; }
		if (!this.prefs.getBoolPref("allowpause")) { this.debug("pausing disabled"); return; }

		this.service.paused = !this.service.paused;		
	},

	handleUserEvent: function(event) {		
		this.service.active = true;
		this.idleTimer.start();
	},

	handleEvent: function(event) {
		this.debug(Date.now() + ": " + event.type + ": " + event.target.tagName + "->" + event.target.id);
		switch (event.type) {
			case "focus":
				this.handleUserEvent(event);
				break;
			case "blur":				
				this.service.active = false;
				this.idleTimer.stop();
				break;
			case "popupshowing":
				this.displayTooltip();
				break;
			case "mousedown":
			case "mouseout": 
			case "DOMMouseScroll":
			case "keydown":
				this.handleUserEvent(event);
				break;
			case "select":				
				this.debug(this.tabbrowser.selectedBrowser.currentURI.spec);
		}
	}
}

var myTkctrlClient = new TkctrlClient();
window.addEventListener("load", function(e) { myTkctrlClient.onLoad(); }, false);
window.addEventListener("unload", function(e) { myTkctrlClient.onUnload(); }, false);

/**********************************************************
 **********************************************************/

const TKCTRL_DISPLAY = "tkctrl-display";

function Observer(parent)
{
	this.parent = parent;
	this.register();
}
Observer.prototype = {
	toString: function() { return "tkctrl observer" },
	debug: function(s) {},
	observe: function(subject, topic, data) {		
		switch (topic) {
			case TKCTRL_DISPLAY:				
				this.parent.displayPanel();				
				this.parent.displayTooltip();
				break;
			case "timer-callback":
				this.debug("user now idle");
				this.parent.service.active = false;
				this.parent.service.decrement(this.parent.idleTimer.idleTimeout);
				break;
		}
	},
	register: function() {
		this.debug("register")
		var observerService = CC[TKCTRL_OBSERVICE_CID]
	                          .getService(CI.nsIObserverService);
		observerService.addObserver(this, TKCTRL_DISPLAY, false);
	},
	unregister: function() {
		this.debug("unregister");
		var observerService = CC[TKCTRL_OBSERVICE_CID]
	                            .getService(CI.nsIObserverService);
		observerService.removeObserver(this, TKCTRL_DISPLAY);
	}
}

function IdleTimer(prefs, observer) { this.prefs = prefs; this.observer = observer }
IdleTimer.prototype = {
	toString: function() { return "tkctrl idle"; },
	mTimer: null,
	mTimeout: 120,
	get idleTimeout() { return this.mTimeout; },
	start: function () {
		if (!this.mTimer) this.mTimer = CC[TKCTRL_TIMER_CID].createInstance(CI.nsITimer);
		this.mTimeout = this.prefs.getIntPref("idletimeout");
		this.stop();
		this.debug("starting with timeout: " + this.mTimeout);
		this.mTimer.init(this.observer, this.mTimeout * 1000, this.mTimer.TYPE_ONE_SHOT);
	},
	stop: function() {
		this.debug("cancelling");
		this.mTimer.cancel();
	}
}

/*************
 *************/

function addLeadingZero(x) {
	return ((x >= 0 && x <= 9) ? "0" : "") + x;
} 

function formatTime(s, showSeconds) {
	var seconds = s % 60;
	var minutes = Math.floor(s/60) % 60;
	var hours = Math.floor(s/3600);
	
	var formattedTime;
	
	if (hours > 0) 
		formattedTime = hours + ":" + addLeadingZero(minutes);
	else
		formattedTime = minutes;
	
	if (showSeconds) formattedTime += ":" + addLeadingZero(seconds);
	
	return formattedTime;
}

/**
 * A funny debug function factory 
 */
(function () {
var objects = [TkctrlClient, Observer, IdleTimer];
for each (var obj in objects) {
	obj.prototype.debug = tkctrlDEBUG ? function (s) { dump(this + ": " + s + "\n"); }
									  : function (s) {}
}
})();
